#!/bin/bash
#
# This script enrolls the identities of the organizations to fetch the certs for them.

source ./utils.sh

# Prints the "directory existing" hint.
printDirectoryExistingHint() {
    local readonly IDENTITY_DISPLAY_NAME=$1
    shift

    printf "The cert directory for '%s' seems to already exists. Delete it first if you'd like to reenroll this identity.\n" ${IDENTITY_DISPLAY_NAME}
}

# Returns 1 if the directory for the identity exists.
checkExistence() {
    local readonly ID_TYPE=$1
    shift
    local readonly DIR_NAME=$1
    shift

    # Determine the part that is either "peers" or "users" in the output directory
    local TYPE_IN_DIR=peers
    if [ ${ID_TYPE} == client ] || [ ${ID_TYPE} == admin ]; then
        TYPE_IN_DIR=users
    elif [ ${ID_TYPE} == orderer ]; then
        TYPE_IN_DIR=orderers
    fi

    if [ -d "${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}" ]; then
        return 1
    fi
}

# Enrolls an identity to fetch the cert files for it.
enrollIdentityCert() {
    local IS_CSR_HOSTS_SPECIFIED=false

    local readonly ID_NAME=$1
    shift
    local readonly ID_SECRET=$1
    shift
    local readonly ID_TYPE=$1
    shift
    local readonly DIR_NAME=$1
    shift
    local readonly IS_ENROLLMENT_PROFILE_TLS=$1
    shift
    if [ $# -ge 1 ]; then
        local readonly CSR_HOSTS=$1
        shift
        IS_CSR_HOSTS_SPECIFIED=true
    fi

    # Determine the part that is either "peers" or "users" in the output directory
    local TYPE_IN_DIR=peers
    if [ ${ID_TYPE} == client ] || [ ${ID_TYPE} == admin ]; then
        TYPE_IN_DIR=users
    elif [ ${ID_TYPE} == orderer ]; then
        TYPE_IN_DIR=orderers
    fi

    if [ ${IS_CSR_HOSTS_SPECIFIED} == true ]; then
        if [ ${IS_ENROLLMENT_PROFILE_TLS} != true ]; then
            # MSP + CSR hosts
            fabric-ca-client enroll -u https://${ID_NAME}:${ID_SECRET}@localhost:${FABRIC_CA_SERVER_PORT} --caname ${FABRIC_CA_SERVER_CA_NAME} -M ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/msp --csr.hosts ${CSR_HOSTS} --tls.certfiles ${WORKING_DIR}/server/${ORG_NAME}/tls-cert.pem >/dev/null 2>&1
        else
            # TLS + CSR hosts
            fabric-ca-client enroll -u https://${ID_NAME}:${ID_SECRET}@localhost:${FABRIC_CA_SERVER_PORT} --caname ${FABRIC_CA_SERVER_CA_NAME} -M ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls --enrollment.profile tls --csr.hosts ${CSR_HOSTS} --csr.hosts localhost --tls.certfiles ${WORKING_DIR}/server/${ORG_NAME}/tls-cert.pem >/dev/null 2>&1
        fi
    else
        if [ ${IS_ENROLLMENT_PROFILE_TLS} != true ]; then
            # MSP w/o CSR hosts
            fabric-ca-client enroll -u https://${ID_NAME}:${ID_SECRET}@localhost:${FABRIC_CA_SERVER_PORT} --caname ${FABRIC_CA_SERVER_CA_NAME} -M ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/msp --tls.certfiles ${WORKING_DIR}/server/${ORG_NAME}/tls-cert.pem >/dev/null 2>&1
        else
            # TLS w/o CSR hosts
            fabric-ca-client enroll -u https://${ID_NAME}:${ID_SECRET}@localhost:${FABRIC_CA_SERVER_PORT} --caname ${FABRIC_CA_SERVER_CA_NAME} -M ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls --enrollment.profile tls --tls.certfiles ${WORKING_DIR}/server/${ORG_NAME}/tls-cert.pem >/dev/null 2>&1
        fi
    fi

    return $?
}

# This helper function wraps `enrollIdentity()` with text responses.
enrollIdentityWithTextResponse() {
    local readonly IDENTITY_DISPLAY_NAME=$1
    shift
    local readonly ID_NAME=$1
    shift
    local readonly ID_SECRET=$1
    shift
    local readonly ID_TYPE=$1
    shift
    local readonly DIR_NAME=$1
    shift
    local readonly IS_ENROLLMENT_PROFILE_TLS=$1
    shift
    if [ $# -ge 1 ]; then
        local readonly CSR_HOSTS=$1
        shift
    fi

    # Determine the display name for the enrollment profile
    local ENROLLMENT_PROFILE_DISPLAY_NAME=MSP
    if [ ${IS_ENROLLMENT_PROFILE_TLS} != true ]; then
        ENROLLMENT_PROFILE_DISPLAY_NAME=TLS
    fi

    printf "Enrolling ${ENROLLMENT_PROFILE_DISPLAY_NAME} cert files for '${IDENTITY_DISPLAY_NAME}'..."
    enrollIdentityCert ${ID_NAME} ${ID_SECRET} ${ID_TYPE} ${DIR_NAME} ${IS_ENROLLMENT_PROFILE_TLS} ${CSR_HOSTS}
    local RET_VAL=$?

    if [ $? -ne 0 ]; then
        printf "\rError enrolling ${ENROLLMENT_PROFILE_DISPLAY_NAME} cert files for '${IDENTITY_DISPLAY_NAME}'.\n"
        return RET_VAL
    else
        printf "\rDone enrolling ${ENROLLMENT_PROFILE_DISPLAY_NAME} cert files for '${IDENTITY_DISPLAY_NAME}'.\n"
    fi
}

reshapeStructure() {
    local readonly IDENTITY_DISPLAY_NAME=$1
    shift
    local readonly ID_TYPE=$1
    shift
    local readonly DIR_NAME=$1
    shift

    # Determine the part that is either "peers" or "users" in the output directory
    local TYPE_IN_DIR=peers
    if [ ${ID_TYPE} == client ] || [ ${ID_TYPE} == admin ]; then
        TYPE_IN_DIR=users
    elif [ ${ID_TYPE} == orderer ]; then
        TYPE_IN_DIR=orderers
    fi

    printf "Reshaping the structure of the cert files for '${IDENTITY_DISPLAY_NAME}'..."

    # Copy the NodeOU config file
    cp ${FABRIC_CA_CLIENT_HOME}/msp/config.yaml ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/msp/

    # Copy the TLSCA cert file to "msp/tlscacerts"
    mkdir ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/msp/tlscacerts
    cp ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/tlscacerts/* ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/msp/tlscacerts/tlsca.${FABRIC_CA_CLIENT_CSR_CN}-cert.pem

    # Reshape the "tls" folder
    cp ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/tlscacerts/* ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/ca.crt
    mv ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/keystore/* ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/server.key
    mv ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/signcerts/* ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/server.crt
    rm -rf ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/cacerts
    rm -rf ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/keystore
    rm -rf ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/signcerts
    rm -rf ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/tlscacerts
    rm -rf ${FABRIC_CA_CLIENT_HOME}/${TYPE_IN_DIR}/${DIR_NAME}/tls/user

    printf "\rDone reshaping the structure of the cert files for '${IDENTITY_DISPLAY_NAME}'.\n"
}

# Enrolls cert files for the identities of the organization indicated by `$ORG_NAME`.
enrollCerts() {
    declare -i local RET_VAL=0
    declare -i local IS_EXISTING
    declare -i local ENROLLMENT_RET_VAL=0

    if [ ${ORG_NAME} != "ordererOrg" ]; then
        ENROLLMENT_RET_VAL=0
        checkExistence "peer" "peer0.${ORG_NAME}.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "peer0.${ORG_NAME}.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "peer0.${ORG_NAME}.lab805.com" "peer0" "peer0pw" "peer" "peer0.${ORG_NAME}.lab805.com" false "peer0.${ORG_NAME}.lab805.com"
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "peer0.${ORG_NAME}.lab805.com" "peer0" "peer0pw" "peer" "peer0.${ORG_NAME}.lab805.com" true "peer0.${ORG_NAME}.lab805.com"
            ENROLLMENT_RET_VAL+=$?
            
            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "peer0.${ORG_NAME}.lab805.com" "peer" "peer0.${ORG_NAME}.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi
        
        ENROLLMENT_RET_VAL=0
        checkExistence "peer" "peer1.${ORG_NAME}.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "peer1.${ORG_NAME}.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "peer1.${ORG_NAME}.lab805.com" "peer1" "peer1pw" "peer" "peer1.${ORG_NAME}.lab805.com" false "peer1.${ORG_NAME}.lab805.com"
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "peer1.${ORG_NAME}.lab805.com" "peer1" "peer1pw" "peer" "peer1.${ORG_NAME}.lab805.com" true "peer1.${ORG_NAME}.lab805.com"
            ENROLLMENT_RET_VAL+=$?

            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "peer1.${ORG_NAME}.lab805.com" "peer" "peer1.${ORG_NAME}.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi

        ENROLLMENT_RET_VAL=0
        checkExistence "client" "User1@${ORG_NAME}.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "User1@${ORG_NAME}.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "User1@${ORG_NAME}.lab805.com" "user1" "user1pw" "client" "User1@${ORG_NAME}.lab805.com" false
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "User1@${ORG_NAME}.lab805.com" "user1" "user1pw" "client" "User1@${ORG_NAME}.lab805.com" true
            ENROLLMENT_RET_VAL+=$?

            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "User1@${ORG_NAME}.lab805.com" "client" "User1@${ORG_NAME}.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi

        ENROLLMENT_RET_VAL=0
        checkExistence "admin" "Admin@${ORG_NAME}.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "Admin@${ORG_NAME}.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "Admin@${ORG_NAME}.lab805.com" "${ORG_NAME}admin" "${ORG_NAME}adminpw" "admin" "Admin@${ORG_NAME}.lab805.com" false
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "Admin@${ORG_NAME}.lab805.com" "${ORG_NAME}admin" "${ORG_NAME}adminpw" "admin" "Admin@${ORG_NAME}.lab805.com" true
            ENROLLMENT_RET_VAL+=$?
            
            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "Admin@${ORG_NAME}.lab805.com" "admin" "Admin@${ORG_NAME}.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi
    else
        ENROLLMENT_RET_VAL=0
        checkExistence "orderer" "orderer.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "orderer.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "orderer.lab805.com" "orderer" "ordererpw" "orderer" "orderer.lab805.com" false "orderer.lab805.com"
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "orderer.lab805.com" "orderer" "ordererpw" "orderer" "orderer.lab805.com" true "orderer.lab805.com"
            ENROLLMENT_RET_VAL+=$?

            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "orderer.lab805.com" "orderer" "orderer.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi

        ENROLLMENT_RET_VAL=0
        checkExistence "orderer" "orderer2.lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "orderer2.lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "orderer2.lab805.com" "orderer2" "orderer2pw" "orderer" "orderer2.lab805.com" false "orderer2.lab805.com"
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "orderer2.lab805.com" "orderer2" "orderer2pw" "orderer" "orderer2.lab805.com" true "orderer2.lab805.com"
            ENROLLMENT_RET_VAL+=$?

            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "orderer2.lab805.com" "orderer" "orderer2.lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi

        ENROLLMENT_RET_VAL=0
        checkExistence "admin" "Admin@lab805.com"
        if [ $? -ne 0 ]; then
            printDirectoryExistingHint "Admin@lab805.com"
            RET_VAL+=1
        else
            enrollIdentityWithTextResponse "Admin@lab805.com" "ordererAdmin" "ordererAdminpw" "admin" "Admin@lab805.com" false
            ENROLLMENT_RET_VAL+=$?
            enrollIdentityWithTextResponse "Admin@lab805.com" "ordererAdmin" "ordererAdminpw" "admin" "Admin@lab805.com" true
            ENROLLMENT_RET_VAL+=$?

            if [ ${ENROLLMENT_RET_VAL} -eq 0 ]; then
                reshapeStructure "Admin@lab805.com" "admin" "Admin@lab805.com"
            fi

            RET_VAL+=${ENROLLMENT_RET_VAL}
        fi
    fi
}

# Main script
checkBinAvailability || {
    printf "Error: Fabric CA binaries not available.\n"
    exit 1
}

WORKING_DIR=${PWD}

IS_ALL_SUCCESS=true
for ORG_NAME in "org1" "org2" "ordererOrg"; do
    setServerEnvVars
    setClientHome

    enrollCerts || IS_ALL_SUCCESS=false
done

if [ ${IS_ALL_SUCCESS} == false ]; then
    exit 2
fi
